/**
 * @addtogroup brd_canfd
 * brd_canfd
 * @{
 */
/**
 * @file brd_canfd.h
 * @brief CANFD板级接口
 * @par 修改日志
 * <table>
 * <tr><th>Date <th>Version <th>Author <th>Description
 * <tr><td>2022-03-01 <td>1.0 <td>软件工程院 <td>创建初始版本
 * @par 示例
 * @code
 * 初始化一个CAN设备.默认波特率为250K
   TCanfdData tx_buf[50];
   TCanfdData rx_buf[50];
   static void XXX_OnCanfdRecv(Brd_THandle handle)
   {
       // 发送事件
   }

   Brd_THandle handle = Brd_CanfdCreate(id, tx_buf,sizeof(tx_buf),rx_buf,sizeof(rx_buf));
   ...
   Brd_CanfdSetEventReceiver(handle, xxx);
   Brd_CanfdSetRecvEvent(handle, XXX_OnCanfdRecv);
   ...
   Brd_CanfdPowerSupply(handle, kBrd_PowerSupplyOn);
   Brd_CanfdSetBaudRate(handle, kBrd_CanfdBaudRate250k);
   Brd_CanfdOpen(handle);
   ...
   // Brd_CanfdWrite...
   ...
   Brd_CanfdClose(handle);
   Brd_CanfdPowerSupply(handle, kBrd_PowerSupplyOff);
   ...
   Brd_CanfdFree(handle);
   ...
 * @endcode
 * @copyright 杭州鸿泉物联网技术股份有限公司

 */

#ifndef _BRD_CANFD_H_
#define _BRD_CANFD_H_

#include <ofc_types.h>
#include <canfd_def.h>
#include "brd_common.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * CAN数据发送后的事件,用于告知这个数据报是否发送成功
 * @param handle: 句柄
 * @param data_id: CAN数据id即为调用CAN发送时[TCanfdData.data_id](@ref TCanfdDataTag)
 * @param success: 用于表示数据是否发送成功,true表示发送成功,否则表示发送失败
 * @return 无返回值
 */
typedef void (*Brd_TOnCanfdSent) (Brd_THandle handle, UInt32 data_id, Bool success);

/**
 * 收到CAN数据时的事件,主动发起通知，告知有收到数据
 * @param handle: 句柄
 * @return 无返回值
 */
typedef void (*Brd_TOnCanfdRecv) (Brd_THandle handle);

/**
 * CAN总线在Bus off时的触发的事件
 * @param handle: 句柄
 * @return 无返回值
 */
typedef void (*Brd_TOnCanfdBusOff) (Brd_THandle handle);

/**
 * 波特率侦测事件,用于告知当前的波特率是否与总线匹配
 * @param handle: 句柄
 * @param success: 用于表示当前波特率与总线是否匹配,true表示匹配,否则表示不匹配
 * @return 无返回值
 */
typedef void (*Brd_TOnCanfdDetect) (Brd_THandle handle, Bool success);

/**
 * 根据标识创建句柄
 * @param id: 标识, 参见[brd_def](@ref Brd_TCanfdIdTag)
 * @param tx_buf: 发送缓冲区,不允许为空
 * @param tx_buf_size: 发送缓冲区的大小.缓冲区大小必须是sizeof([TCanfdData](@ref TCanfdDataTag))的整数倍
 * @param rx_buf: 接收缓冲区,不允许为空
 * @param rx_buf_size: 接收缓冲区的大小.缓冲区大小必须是sizeof([TCanfdData](@ref TCanfdDataTag))的整数倍
 * @return 当返回值为非 NULL 时, 表示创建成功, \n
 *         当返回值为 NULL 时, 表示创建失败, 原因为参数错误
 */
Brd_THandle Brd_CanfdCreate(Int32 id, void *tx_buf, Int32 tx_buf_size, void *rx_buf, Int32 rx_buf_size);

/**
 * 释放句柄
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示成功 \n
 *         当返回值 < 0 时, 表示失败参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdFree(Brd_THandle handle);

/**
 * 获取CANFD模块的编号(索引)
 * @param handle: 句柄
 * @return 0: 第一路CAN, 1: 第二路CAN, ...
 */
Byte Brd_CanfdBusNo(Brd_THandle handle);

/**
 * 获取事件接收者
 * @param handle: 句柄
 * @return 当返回值为非 NULL 时, 表示事件接收者 \n
 *         当返回值为 NULL 时, 表示未设置过事件接收者
 */
void *Brd_CanfdEventReceiver(Brd_THandle handle);

/**
 * 设置事件接收者
 * @param handle: 句柄
 * @param receiver: 事件接收者
 * @return 无返回值 
 */
void Brd_CanfdSetEventReceiver(Brd_THandle handle, void *receiver);

/**
 * 设置发送完成后触发的事件
 * @note    当事件产生时直接告知用户去处理, 在中断函数里面调用本函数, 因此需要用户保持警惕,
 *          切勿处理高延迟或不能在中断里面处理的操作
 * @param handle: 句柄
 * @param on_event: 事件方法
 * @return 无返回值 
 */
void Brd_CanfdSetSentEvent(Brd_THandle handle, Brd_TOnCanfdSent on_event);

/**
 * 设置接收到数据后触发的事件
 * @note    当事件产生时直接告知用户去处理, 在中断函数里面调用本函数, 因此需要用户保持警惕,
 *          切勿处理高延迟或不能在中断里面处理的操作
 * @param handle: 句柄
 * @param on_event: 事件方法
 * @return 无返回值 
 */
void Brd_CanfdSetRecvEvent(Brd_THandle handle, Brd_TOnCanfdRecv on_event);

/**
 * 设置总线关闭错误后触发的事件
 * @note    当事件产生时直接告知用户去处理, 在中断函数里面调用本函数, 因此需要用户保持警惕,
 *          切勿处理高延迟或不能在中断里面处理的操作
 * @param handle: 句柄
 * @param on_event: 事件方法
 * @return 无返回值 
 */
void Brd_CanfdSetBusOffEvent(Brd_THandle handle, Brd_TOnCanfdBusOff on_event);

/**
 * 设置波特率检测后触发的事件
 * @note    当事件产生时直接告知用户去处理, 在中断函数里面调用本函数, 因此需要用户保持警惕,
 *          切勿处理高延迟或不能在中断里面处理的操作
 * @param handle: 句柄
 * @param on_event: 事件方法
 * @return 无返回值 
 */
void Brd_CanfdSetDetectEvent(Brd_THandle handle, Brd_TOnCanfdDetect on_event);

/**
 * 设备供电
 * @note 设备操作的前提, 需要先供电, 所有操作完成后需要停止供电以降低功耗
 * @param handle: 句柄
 * @param power : 设备供电类型, 参见[brd_def](@ref Brd_TPowerSupplyTag)
 * @return 当返回值 >= 0 时, 表示控制成功 \n
 *         当返回值 < 0 时, 表示控制失败参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdPowerSupply(Brd_THandle handle, Int32 power);

/**
 * 获取当前CAN的波特率. 设备的默认波特率为250000
 * @param handle: 句柄
 * @param n_baudrate: 标称波特率, 用于仲裁域
 * @param fd_baudrate: 灵活速率波特率, 用于数据域
 * @return 当返回值 >= 0 时, 表示成功 \n
 *         当返回值 < 0 时, 表示失败参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdBaudRate(Brd_THandle handle, UInt32 *n_baudrate, UInt32 *fd_baudrate);

/**
 * 设置CAN总线的波特率.设备的默认波特率为250000
 * @note 仅在调用[Brd_CanfdOpen](@ref Brd_CanfdOpen)前设置有效
 * @param handle: 句柄
 * @param n_baudrate: 标称波特率, 用于仲裁域
 * @param fd_baudrate: 灵活速率波特率, 用于数据域
 * @return 当返回值 >= 0 时, 表示成功 \n
 *         当返回值 < 0 时, 表示失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdSetBaudRate(Brd_THandle handle, UInt32 n_baudrate, UInt32 fd_baudrate);

/**
 * 根据采样点设置CAN总线的波特率.
 * @note 
 *   -# 仅在调用[Brd_CanfdOpen](@ref Brd_CanfdOpen)前设置有效
 *   -# 针对有特殊采样点要求的应用
 *   -# 与[Brd_CanfdSetBaudRate](@ref Brd_CanfdSetBaudRate)互斥, 二选一即可
 *   -# 采样点的计算公式: (1 + prop_seg + phase_seg1) / (1 + prop_seg + phase_seg1 + phase_seg2)
 *   -# 波特率的计算公式: 波特率 = CAN总线频率 / (div * (1 + prop_seg + phase_seg1 + phase_seg2))
 *   -# 同时设置n_baudrate和fd_baudrate
 * @param handle: 句柄
 * @param div: 标称波特率分频值
 * @param fd_div: 灵活速率波特率分频值
 * @param prop_seg: 传输段, 单位为tq
 * @param phase_seg1: 相位段1, 单位为tq
 * @param phase_seg2: 相位段2, 单位为tq
 * @return 当返回值 > 0 时, 表示实际的波特率 \n
 *         当返回值 <= 0 时, 表示设置失败, 无法计算出正确的波特率
 */
Int32 Brd_CanfdSetBaudRateEx(Brd_THandle handle, Byte div, Byte fd_div, Byte prop_seg, Byte phase_seg1, Byte phase_seg2);

/**
 * 返回当前是否处于busoff状态
 * @note 仅当BusOff恢复模式为手工模式,且设置了[Brd_TOnCanfdBusOff](@ref Brd_TOnCanfdBusOff)事件,BusOff出现时才会返回True
 * @param handle: 句柄
 * @return 当返回值 True 时, 表示正处于busoff状态 \n
 *         当返回值 False 时, 表示未处于busoff状态
 */
Bool Brd_CanfdBusOff(Brd_THandle handle);

/**
 * 获取当前是否为自动从Bus Off状态恢复(默认为是)
 * @param handle: 句柄
 * @return 返回 True, 表示自动恢复 \n
 *         返回 False, 表示手动恢复
 */
Bool Brd_CanfdAutoRecover(Brd_THandle handle);

/**
 * 设置CAN模块处于Bus Off时,是否自动从Bus Off状态恢复
 * @note 
 *  -# 如果禁用自动恢复,则需要在BusOff后调用[Brd_CanfdBusOffRecover](@ref Brd_CanfdBusOffRecover)来从BusOff状态恢复.
 *  -# 仅在调用[Brd_CanfdOpen](@ref Brd_CanfdOpen)前调用有效
 *  -# 如果禁用自动恢复,则必须设置[Brd_TOnCanfdBusOff](@ref Brd_TOnCanfdBusOff)事件,否则设置无效
 * @param handle: 句柄
 * @param auto_recover: True: 自动从Bus Off状态恢复; False: 需手动恢复
 * @return 无返回值
 */
void Brd_CanfdSetAutoRecover(Brd_THandle handle, Bool auto_recover);

/**
 * 手动将Bus Off状态恢复到正常状态
 * @note 
     1.仅在Bus Off状态下调用
     2.Bus Off状态需要经过128个序列的,每个序列11个隐性位之后才能恢复.在这之前调用本函数,实际上跟自动恢复一样
 * @param handle: 句柄
 * @return 无返回值
 */
void Brd_CanfdBusOffRecover(Brd_THandle handle);

/**
 * 获取当前是否为波特率侦测模式(默认为否)
 * @param handle: 句柄
 * @return 返回True表示自动侦测波特率模式 \n
 *         返回False表示正常收发模式
 */
Bool Brd_CanfdDetectMode(Brd_THandle handle);

/**
 * 设置为自动侦测波特率模式或者正常收发模式
 * @note 仅在调用[Brd_CanfdOpen](@ref Brd_CanfdOpen)前调用有效
 * @param handle: 句柄
 * @param detect: True: 自动侦测波特率模式; False: 正常收发模式
 * @return 无返回值
 */
void Brd_CanfdSetDetectMode(Brd_THandle handle, Bool detect);

/**
 * 打开CAN设备,用于数据收发或者用于波特率侦测
 * @note 波特率自动侦测模式注意事项
 *  -# 需要CAN设备关闭的情况下执行
 *  -# 执行完毕后需要调用[Brd_CanfdClose](@ref Brd_CanfdClose)关闭侦测模式后方可再打开CAN设备
 *  -# 侦测时,会自动从BusOff状态恢复
 *  -# 侦测时,[Brd_TOnCanfdSent](@ref Brd_TOnCanfdSent), [Brd_TOnCanfdBusOff](@ref Brd_TOnCanfdBusOff)事件均不会调用,但[Brd_TOnCanfdRecv](@ref Brd_TOnCanfdRecv)事件还是会调用
 *  -# 侦测时,会产生一个或者多个[Brd_TOnCanfdDetect](@ref Brd_TOnCanfdDetect)事件,用于告知侦测的结果
 *  -# 如果对端只有一个CAN节点在发数据,即发送的数据没有应答是无法自动侦测的(控制器在收到正确但未应答的报文,只会报Bit0错误;总线波特率比设置的波特率大的时候,有可能不产生错误中断)
 * @note 波特率自动侦测模式侦测方式
 *  -# 设置[Brd_TOnCanfdDetect](@ref Brd_TOnCanfdDetect)事件
 *  -# 调用[Brd_CanfdSetDetectMode](@ref Brd_CanfdSetDetectMode),参数detect为True
 *  -# 调用[Brd_CanfdSetBaudRate](@ref Brd_CanfdSetBaudRate)设置一种波特率(注意: 检测时波特率务必由低到高,否则可能会出错)
 *  -# 调用[Brd_CanfdOpen](@ref Brd_CanfdOpen),开始检测该波特率是否正确
 *  -# 通过[Brd_TOnCanfdDetect](@ref Brd_TOnCanfdDetect)事件得知当前波特率检查的结果(需要外设有数据发送才能侦测,且回调该事件)
 *  -# 在[Brd_TOnCanfdDetect](@ref Brd_TOnCanfdDetect)事件中设置TSfEvent来通知检测结果
 *  -# 主程序在收到事件后判断是否检测成功
 *  -# 如果检测失败,则调用[Brd_CanfdClose](@ref Brd_CanfdClose)关闭检测,然后跳转到步骤3
 *  -# 如果检测成功,则调用[Brd_CanfdClose](@ref Brd_CanfdClose)关闭检测
 
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示打开成功 \n
 *         当返回值 < 0 时, 表示打开失败, 参见[brd_def](@ref Brd_TErrorCode)
 */
Int32 Brd_CanfdOpen(Brd_THandle handle);

/**
 * 设备关闭
 * @param handle: 句柄
 * @return 当返回值 >= 0 时, 表示关闭成功 \n
 *         当返回值 < 0 时, 表示关闭失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdClose(Brd_THandle handle);

/**
 * 读取收到的CAN数据
 * @note 接收报文的时间戳来自g_timer_srv的tick,故打开CAN设备前需要先初始化相关定时器设备
 * @param handle: 句柄
 * @param items: 存放CAN数据的缓冲区
 * @param count: Buf能容纳多少个[TCanfdData](@ref TCanfdDataTag)类型的数据
 * @return 当返回值 >= 0 时, 表示实际读取到的[TCanfdData](@ref TCanfdDataTag)类型的数据个数 \n
 *         当返回值 < 0 时, 表示设置失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdRead(Brd_THandle handle, TCanfdData *items, Int32 count);

/**
 * 写CAN数据到发送队列.写完后会自动开始发送
 * @note 如果是波特率侦测模式,则数据无法发送
 * @param handle: 句柄
 * @param items: 需要发送的CAN数据
 * @param count: Data包含的[TCanfdData](@ref TCanfdDataTag)类型的数据的个数
 * @return 当返回值 >= 0 时, 表示实际发送的[TCanfdData](@ref TCanfdDataTag)类型的数据个数 \n
 *         当返回值 < 0 时, 表示设置失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdWrite(Brd_THandle handle, const TCanfdData *items, Int32 count);

/**
 * 优先发送CAN数据.
 * @note 函数与[Brd_CanfdWrite](@ref Brd_CanfdWrite)的区别
 * 1. [Brd_CanfdWrite](@ref Brd_CanfdWrite)把CAN数据放入发送队列,而本函数不把数据加入发送队列
 * 2. 本函数写入的CAN数据优先发送
 * 3. [Brd_CanfdWrite](@ref Brd_CanfdWrite)支持一次性写入多个CAN数据,而本函数只能写入一个数据
 * 4. 如果本函数上一次的数据还没有发送,则直接返回失败
 * 5. 如果是波特率侦测模式,则数据无法发送
 * @param handle: 句柄
 * @param item: 需要发送的CAN数据
 * @return 当返回值 >= 0 时, 表示写入成功,等待优先发送 \n
 *         当返回值 < 0 时, 表示写入失败, 参见[brd_def](@ref Brd_TErrorCodeTag)
 */
Int32 Brd_CanfdWritePreemptive(Brd_THandle handle, const TCanfdData *item);

/**
 * 取消当前正在发送的CAN报文
 * @note 对于队列中data_id不为0的报文会产生[Brd_TOnCanfdSent](@ref Brd_TOnCanfdSent)事件
 * @param handle: 句柄
 * @return 无返回值
 */
void Brd_CanfdAbortSend(Brd_THandle handle);

/**
 * 清除发送队列中的所有报文(包括优先发送的数据);
 * @note
 *  1. 仅在BusOff状态下调用有效
 *  2. 对于队列中data_id不为0的报文会产生[Brd_TOnCanfdSent](@ref Brd_TOnCanfdSent)事件
 * @param handle: 句柄
 * @return 无返回值
 */
void Brd_CanfdClearSendFifo(Brd_THandle handle);

#ifdef __cplusplus
}  ///< extern "C"
#endif

#endif /// _BRD_CANFD_H_
/**
 * @} 
 */
